package com.iplant.wms.serviceImpl.dao.brm;

import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.mss.MSSMaterial;
import com.iplant.wms.service.basicenum.wms.WMSSpaceLimits;
import com.iplant.wms.service.basicenum.wms.WMSStationLimits;
import com.iplant.wms.service.po.brm.BRMShelvesProp;
import com.iplant.wms.service.po.mfs.WMSStoreStation;
import com.iplant.wms.service.po.mss.MSSMaterialStation;
import com.iplant.wms.service.po.pkg.MSSPackageProp;
import com.iplant.wms.service.po.wms.WMSStock;
import com.iplant.wms.service.po.wms.WMSStockRecord;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@DBBaseDAO(BRMShelvesProp.class)
public class BRMShelvesPropDAO extends BaseDAO {

    private static BRMShelvesPropDAO Instance = null;


    private BRMShelvesPropDAO() {
        super("");
        this.Init();
    }

    public static BRMShelvesPropDAO getInstance() {
        if (Instance == null) {
            Instance = new BRMShelvesPropDAO();
        }
        return Instance;
    }


    public void BRM_DeleteShelvesProp(BMSEmployee wLoginUser, int wRuleID, OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);

        try {
            if (wRuleID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }
            Map<String, Object> wDeleteParams = new HashMap<>();
            wDeleteParams.put("RuleID", wRuleID);
            this.Delete(wDeleteParams, " and ID>0 ");

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("BRM_DeleteShelvesProp", ex);
        }
    }


    public List<BRMShelvesProp> BRM_QueryShelvesPropList(
            BMSEmployee wLoginUser, int wRuleID, String wName, String wCode,
            int wActive, Pagination wPagination, OutResult<Integer> wErrorCode) {


        Map<String, Object> wParams = new HashMap<>();

        wParams.put("Name", wName);
        wParams.put("RuleID", wRuleID);
        wParams.put("Code", wCode);
        wParams.put("Active", wActive);

        return this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);
    }


    /**
     * 检验仓库是否还能继续存放  根据库存判断
     *
     * @param wLoginUser
     * @param wStationList
     * @param wStockList
     * @param wBRMShelvesProp
     * @param wOrderType
     * @param ReceiveUnit
     * @param wLoopLevel
     * @param wBatchRuleCode
     * @param wMSSMaterial
     * @param wBatchNo
     * @param wMaterialNumber   上架数量 可不同于收货明细一条 的数量
     * @param wTotalVolume
     * @param wTotalGrossWeight
     * @return
     */
    public List<WMSStoreStation> BRM_CalcReceiveItemStation(
            BMSEmployee wLoginUser, List<WMSStoreStation> wStationList, List<MSSMaterialStation> wMaterialStationList,
            List<WMSStock> wStockList, BRMShelvesProp wBRMShelvesProp, MSSPackageProp wMSSPackageProp,
            int wOrderType, String ReceiveUnit, int wLoopLevel, String wBatchRuleCode,
            MSSMaterial wMSSMaterial, List<MSSMaterial> wMSSMaterialList, String wBatchNo, double wMaterialNumber,
            double wTotalVolume, double wTotalGrossWeight,
            OutResult<Integer> wErrorCode) {
        List<WMSStoreStation> wResult = new ArrayList<>();

        try {
            if (wBRMShelvesProp.BillTypeID > 0) {
                if (wOrderType != wBRMShelvesProp.BillTypeID) {
                    return wResult;
                }
            }
            if (wBRMShelvesProp.LoopTypeID > 0) {
                if (wLoopLevel != wBRMShelvesProp.LoopTypeID) {
                    return wResult;
                }
            }
            if (StringUtils.isNotEmpty(wBRMShelvesProp.PackageLevel)) {
                if (wBRMShelvesProp.PackageLevel.equals(ReceiveUnit)) {
                    return wResult;
                }
            }
            if (StringUtils.isNotEmpty(wBRMShelvesProp.BatchRuleCode)) {
                if (wBRMShelvesProp.BatchRuleCode.equals(wBatchRuleCode)) {
                    return wResult;
                }
            }

            if (wBRMShelvesProp.PickingMode > 0) {
                wStationList.removeIf(p -> p.PickingMode != wBRMShelvesProp.PickingMode);
            }
            if (wBRMShelvesProp.StationTypeID > 0) {
                wStationList.removeIf(p -> (p.TypeID != wBRMShelvesProp.StationTypeID));
            }
            //无效
            if (wBRMShelvesProp.HandlerTypeID > 0) {

            }
            //无效
            if (wBRMShelvesProp.LoopTypeID > 0) {

            }

            List<WMSStockRecord> wWMSStockRecordList = wStockList.stream().flatMap(p -> p.StockRecordList.stream()).collect(Collectors.toList());

            Map<Integer, List<WMSStockRecord>> wStockListMap =
                    wWMSStockRecordList.stream().collect(Collectors.groupingBy(p -> p.StoreStationID));

            if (wBRMShelvesProp.MaxMixMaterial > 0) {
                //
                wStationList.removeIf(p -> wStockListMap.containsKey(p.ID)
                        && wStockListMap.get(p.ID).stream().filter(q -> !q.MaterialCode.equals(wMSSMaterial.Code))
                        .collect(Collectors.groupingBy(q -> q.MaterialCode)).size() >= wBRMShelvesProp.MaxMixMaterial);
            }
            if (wBRMShelvesProp.MaxMixBatch > 0) {
                //
                wStationList.removeIf(p -> wStockListMap.containsKey(p.ID)
                        && wStockListMap.get(p.ID).stream().filter(q -> !q.BatchRecordCode.equals(wBatchNo))
                        .collect(Collectors.groupingBy(q -> q.BatchRecordCode)).size() >= wBRMShelvesProp.MaxMixBatch);
            }
            if (StringUtils.isNotEmpty(wBRMShelvesProp.StationLimit)) {

                for (Integer wStationLimit : StringUtils.parseIntList(wBRMShelvesProp.StationLimit, ",")) {
                    switch (WMSStationLimits.getEnumType(wStationLimit)) {

                        case Empty:
                            wStationList.removeIf(p -> wStockListMap.containsKey(p.ID));
                            break;
                        case NotMixMaterial:
                            wStationList.removeIf(p -> wStockListMap.containsKey(p.ID)
                                    && wStockListMap.get(p.ID).stream()
                                    .filter(q -> !q.MaterialCode.equals(wMSSMaterial.Code))
                                    .collect(Collectors.groupingBy(q -> q.MaterialCode)).size() >= 1);
                            break;
                        case NotMixBatch:
                            wStationList.removeIf(p -> wStockListMap.containsKey(p.ID)
                                    && wStockListMap.get(p.ID).stream().filter(q -> !q.BatchRecordCode.equals(wBatchNo))
                                    .collect(Collectors.groupingBy(q -> q.BatchRecordCode)).size() >= 1);
                            break;
                        case SameMaterial:
                            wStationList.removeIf(p -> !wStockListMap.containsKey(p.ID)
                                    || !wStockListMap.get(p.ID).stream()
                                    .filter(q -> q.MaterialCode.equals(wMSSMaterial.Code))
                                    .findFirst()
                                    .isPresent());
                            break;
                        case SameBatch:
                            wStationList.removeIf(p -> !wStockListMap.containsKey(p.ID)
                                    || !wStockListMap.get(p.ID).stream()
                                    .filter(q -> q.MaterialCode.equals(wMSSMaterial.Code) && q.BatchRecordCode.equals(wBatchNo))
                                    .findFirst()
                                    .isPresent());
                            break;
                        case SameMaterialGroup:
                            //获取物料同组物料列表

                            if (wMSSMaterialList == null || wMSSMaterialList.size() <= 0) {
                                return wResult;
                            }
                            List<String> wMaterialNoList = wMSSMaterialList.stream().map(p -> p.Code).collect(
                                    Collectors.toList());

                            wStationList.removeIf(p -> !wStockListMap.containsKey(p.ID)
                                    || !wStockListMap.get(p.ID).stream()
                                    .filter(q -> wMaterialNoList.contains(q.MaterialCode))
                                    .findFirst()
                                    .isPresent());


                            break;
                        case Default:
                            break;
                        default:
                            break;
                    }
                }

            }
            if (StringUtils.isNotEmpty(wBRMShelvesProp.SpaceLimit)) {

                for (Integer wSpaceLimit : StringUtils.parseIntList(wBRMShelvesProp.SpaceLimit, ",")) {
                    switch (WMSSpaceLimits.getEnumType(wSpaceLimit)) {

                        case Volume:

                            if (wTotalVolume <= 0) {
                                wTotalVolume =
                                        wMSSMaterial.Length * wMSSMaterial.Width * wMSSMaterial.Height * (
                                                wMSSPackageProp == null || wMSSPackageProp.Volume <= 0 ?
                                                        wMaterialNumber : wMSSPackageProp.Volume);
                            }
                            double wTotalVolumeT = wTotalVolume;

                            wStationList.removeIf(p -> {
                                if (wStockListMap.containsKey(p.ID)) {
                                    return (p.Length * p.Width * p.Height) < (wStockListMap.get(p.ID).stream()
                                            .collect(Collectors.summingDouble(q -> q.TotalVolume)) + wTotalVolumeT);
                                } else {
                                    return (p.Length * p.Width * p.Height) < wTotalVolumeT;
                                }
                            });
                            break;
                        case Length:

                            wStationList.removeIf(
                                    p -> p.Length < ((wMSSPackageProp == null || wMSSPackageProp.ContentLength <= 0) ?
                                            wMSSMaterial.Length :
                                            (wMSSPackageProp.ContentLength + wMSSPackageProp.Length)));
                            break;
                        case Weight:
                            if (wTotalGrossWeight <= 0) {
                                wTotalGrossWeight =
                                        wMSSMaterial.GrossWeight * wMaterialNumber;
                            }
                            double wTotalGrossWeightT = wTotalGrossWeight;
                            wStationList.removeIf(p -> p.Bearing < wTotalGrossWeightT);
                            break;
                        case MaterialNum:
                            //数量限定
                            if (wMaterialStationList == null || wMaterialStationList.size() == 0) {
                                //容量为0
                                return wResult;
                            }
                            List<Integer> wStationIDs =
                                    wStationList.stream().map(p -> p.ID).collect(Collectors.toList());
//                            List<Integer> wStationIDList = wMaterialStationList.stream()
//                                    .filter(p -> {
//                                        if (wStationIDs.contains(p.StoreStationID) && p.MaterialVolume > 0) {
//                                            if (wStockListMap.containsKey(p.StoreStationID)) {
//                                                return p.MaterialVolume > (wStockListMap.get(p.StoreStationID).stream()
//                                                        .collect(
//                                                                Collectors.summingDouble(
//                                                                        q -> q.TotalVolume))) + wMaterialNumber;
//                                            } else {
//                                                return p.MaterialVolume > wMaterialNumber;
//                                            }
//                                        } else {
//                                            return false;
//                                        }
//                                    }).map(p -> p.StoreStationID).collect(Collectors.toList());

//                            wStationList.removeIf(p -> !wStationIDList.contains(p));

                            break;
                        case PalletNum:
                            //默认1栈板
//                            wStationList.removeIf(p -> {
//                                if (wStockListMap.containsKey(p.ID) && p.TrayNumber > 0) {
//                                    return (p.TrayNumber) < (wStockListMap.get(p.ID).stream()
//                                            .collect(Collectors.groupingBy(q -> q.PalletCode)).size() + 1);
//                                } else {
//                                    return false;
//                                }
//                            });
                            break;
                        case BoxNum:
                            //默认1箱
//                            wStationList.removeIf(p -> {
//                                if (wStockListMap.containsKey(p.ID) && p.TrayNumber > 0) {
//                                    return (p.BoxNumber) < (wStockListMap.get(p.ID).stream()
//                                            .collect(Collectors.groupingBy(q -> q.BoxCode)).size() + 1);
//                                } else {
//                                    return false;
//                                }
//                            });
                            break;
                        case Height:
                            wStationList.removeIf(
                                    p -> p.Height < ((wMSSPackageProp == null || wMSSPackageProp.ContentHeight <= 0) ?
                                            wMSSMaterial.Height :
                                            (wMSSPackageProp.ContentHeight + wMSSPackageProp.Height)));
                            break;
                        case UnitNum:

//                            wStationList.removeIf(p -> {
//                                if (wStockListMap.containsKey(p.ID) && p.MinPackingNumber > 0) {
//                                    return (p.MinPackingNumber) < (wStockListMap.get(p.ID).stream()
//                                            .collect(Collectors.groupingBy(q -> q.BoxCode)).size() + 1);
//                                } else {
//                                    return false;
//                                }
//                            });
                            break;
                        case Width:
                            wStationList.removeIf(
                                    p -> p.Length < ((wMSSPackageProp == null || wMSSPackageProp.ContentWidth <= 0) ?
                                            wMSSMaterial.Width :
                                            (wMSSPackageProp.ContentWidth + wMSSPackageProp.Width)));
                            break;
                        case Default:
                            break;
                        default:
                            break;
                    }
                }

            }
            //finally
            if (wBRMShelvesProp.SameLimits > 0) {

                Map<Integer, Integer> wStockAreaMap = new HashMap<>();

                for (WMSStoreStation wmsStoreStation : wStationList) {
                    if (!wStockAreaMap.containsKey(wmsStoreStation.StoreAreaID)) {
                        wStockAreaMap.put(wmsStoreStation.StoreAreaID, 0);
                    }
                    if (wStockAreaMap.get(wmsStoreStation.StoreAreaID) < wBRMShelvesProp.SameLimits) {
                        wResult.add(wmsStoreStation);
                    }
                    wStockAreaMap.put(wmsStoreStation.StoreAreaID, wStockAreaMap.get(wmsStoreStation.StoreAreaID) + 1);
                }
            } else {
                wResult = wStationList;
            }
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("BRM_CalcReceiveItemStation", ex);
        }
        return wResult;
    }


    /**
     * 根据同组物料库存所在相邻库位排序
     *
     * @param wLoginUser
     * @param wStationList     可存放库存列表
     * @param wMSSMaterialList 同组物料列表
     * @param wStockList       库存列表
     * @param wStationList     所有库位列表
     * @param wErrorCode
     * @return
     */
    public List<WMSStoreStation> BRM_SortReceiveItemStation(
            BMSEmployee wLoginUser, List<WMSStoreStation> wStoreStationList,
            List<MSSMaterial> wMSSMaterialList, List<WMSStock> wStockList,
            List<WMSStoreStation> wStationList, OutResult<Integer> wErrorCode) {
        try {
            if (wMSSMaterialList == null || wMSSMaterialList.size() <= 0 || wStoreStationList == null
                    || wStoreStationList.size() <= 0 || wStationList == null || wStationList.size() <= 0) {
                return wStoreStationList;
            }
            List<String> wMaterialNoList =
                    wMSSMaterialList.stream().map(p -> p.Code).distinct().collect(Collectors.toList());

            List<Integer> wStationIDList =
                    wStockList.stream().filter(p -> wMaterialNoList.contains(p.MaterialCode)).map(p -> p.StoreStationID)
                            .collect(Collectors.toList());
            if (wStationIDList.size() <= 0) {
                return wStoreStationList;
            }

            List<WMSStoreStation> wStationStockList =
                    wStationList.stream().filter(p -> wStationIDList.contains(p.ID)).collect(Collectors.toList());

            if (wStationStockList.size() <= 0) {
                return wStoreStationList;
            }

            wStoreStationList.sort(
                    Comparator.comparingDouble(p -> this.BRM_CalcStationPositionMin(
                            wLoginUser, p, wStationStockList, wErrorCode)
                    ));

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            log.error("BRM_SortReceiveItemStation", ex);
        }
        return wStoreStationList;
    }

    private double BRM_CalcStationPositionMin(BMSEmployee wLoginUser, WMSStoreStation wWMSStoreStation,
                                              List<WMSStoreStation> wStationList,
                                              OutResult<Integer> wErrorCode) {
        double wResult = -1;
        if (wWMSStoreStation == null || wStationList == null || wStationList.size() <= 0) {
            return wResult;
        }
        double wDouble = -1;
        for (WMSStoreStation wmsStoreStation : wStationList) {
            wDouble = Math.abs(wWMSStoreStation.PositionX - wmsStoreStation.PositionX)
                    + Math.abs(wWMSStoreStation.PositionY - wmsStoreStation.PositionY) + Math.abs(
                    wWMSStoreStation.PositionZ - wmsStoreStation.PositionZ);

            if (wResult < 0 || wDouble < wResult) {
                wResult = wDouble;
            }
        }
        return wResult;
    }

    /**
     * @param wLoginUser
     * @param wStoreStationList 可存放库位列表  包括拣货位 存储位
     * @param wStationList      拣货库位列表
     * @param wErrorCode
     * @return
     */
    public List<WMSStoreStation> BRM_SortReceiveItemStation(BMSEmployee wLoginUser, List<WMSStoreStation> wStoreStationList, List<WMSStoreStation> wStationList,
                                                            OutResult<Integer> wErrorCode) {
        try {
            if (wStoreStationList == null || wStoreStationList.size() <= 0 || wStationList == null || wStationList.size() <= 0) {
                return wStoreStationList;
            }

            wStoreStationList.sort(
                    Comparator.comparingDouble(p -> this.BRM_CalcStationPositionMin(
                            wLoginUser, p, wStationList, wErrorCode)
                    ));

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            log.error("BRM_SortReceiveItemStation", ex);
        }
        return wStationList;
    }


}
